﻿using System.Net.Http.Headers;

namespace JinShun.OA.UI.Apis
{
    public class HttpWebClient
    {

        private IHttpClientFactory _httpClientFactory;
        private readonly ILogger<HttpWebClient> _logger;

        public HttpWebClient(IHttpClientFactory httpClientFactory, ILogger<HttpWebClient> logger)
        {
            _httpClientFactory = httpClientFactory;
            _logger = logger;
        }

        /// <summary>
        /// Get
        /// </summary>
        /// <param name="url"></param>
        /// <param name="dicHeaders"></param>
        /// <param name="timeoutSecond"></param>
        /// <returns></returns>
        public async Task<T> GetAsync<T>(string url, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            try
            {
                var client = BuildHttpClient(dicHeaders, timeoutSecond);
                var response = await client.GetAsync(url);
                var responseContent = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseContent);
                }
                else
                {
                    throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"HttpGet:{url} Error:{ex.ToString()}");
                throw new Exception($"HttpGet:{url} Error", ex);
            }
        }
        /// <summary>
        /// Post
        /// </summary>
        /// <param name="url"></param>
        /// <param name="requestBody"></param>
        /// <param name="dicHeaders"></param>
        /// <param name="timeoutSecond"></param>
        /// <returns></returns>
        public async Task<T> PostAsync<T>(string url, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            try
            {
                var client = BuildHttpClient(null, timeoutSecond);
                //var requestContent = GenerateStringContent(requestBody, dicHeaders);
                var requestContent = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/json");
                var response = await client.PostAsync(url, requestContent);
                var responseContent = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    var result = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseContent);
                    return result;
                }
                else
                {
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"HttpPost:{url},body:{requestBody} Error:{ex.ToString()}");
                return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(ex.ToString());
                //throw new Exception($"HttpPost:{url} Error", ex);
            }
        }
        /// <summary>
        /// Put
        /// </summary>
        /// <param name="url"></param>
        /// <param name="requestBody"></param>
        /// <param name="dicHeaders"></param>
        /// <param name="timeoutSecond"></param>
        /// <returns></returns>
        public async Task<T> PutAsync<T>(string url, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            try
            {
                var client = BuildHttpClient(null, timeoutSecond);
                //var requestContent = GenerateStringContent(requestBody, dicHeaders);
                var requestContent = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/json");
                var response = await client.PutAsync(url, requestContent);
                var responseContent = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    var result = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseContent);
                    return result;
                }
                else
                {
                    throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"HttpPut:{url},Body:{requestBody},  Error:{ex.ToString()}");
                throw new Exception($"HttpPut:{url} Error", ex);
            }
        }

        /// <summary>
        /// Patch
        /// </summary>
        /// <param name="url"></param>
        /// <param name="requestString"></param>
        /// <param name="dicHeaders"></param>
        /// <param name="timeoutSecond"></param>
        /// <returns></returns>
        public async Task<T> PatchAsync<T>(string url, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            try
            {
                var client = BuildHttpClient(null, timeoutSecond);
                var requestContent = GenerateStringContent(requestBody, dicHeaders);
                var response = await client.PatchAsync(url, requestContent);
                var responseContent = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    var result = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseContent);
                    return result;
                }
                else
                {
                    throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"HttpPatch:{url},body:{requestBody}, Error:{ex.ToString()}");
                throw new Exception($"HttpPatch:{url} Error", ex);
            }
        }
        /// <summary>
        /// Delete
        /// </summary>
        /// <param name="url"></param>
        /// <param name="dicHeaders"></param>
        /// <param name="timeoutSecond"></param>
        /// <returns></returns>
        public async Task<T> DeleteAsync<T>(string url, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            try
            {
                var client = BuildHttpClient(dicHeaders, timeoutSecond);
                var response = await client.DeleteAsync(url);
                var responseContent = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    var result = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseContent);
                    return result;
                }
                else
                {
                    throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"HttpDelete:{url}, Error:{ex.ToString()}");
                throw new Exception($"HttpDelete:{url} Error", ex);
            }
        }
        /// <summary>
        /// common request
        /// </summary>
        /// <param name="url"></param>
        /// <param name="method"></param>
        /// <param name="requestBody"></param>
        /// <param name="dicHeaders"></param>
        /// <param name="timeoutSecond"></param>
        /// <returns></returns>
        public async Task<T> ExecuteAsync<T>(string url, HttpMethod method, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            try
            {
                var client = BuildHttpClient(null, timeoutSecond);
                var request = GenerateHttpRequestMessage(url, requestBody, method, dicHeaders);
                Task<HttpResponseMessage> task = client.SendAsync(request);
                task.Wait();
                HttpResponseMessage response = task.Result;
                var responseContent = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    var result = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseContent);
                    return result;
                }
                else
                {
                    throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"{method.ToString()}:{url},body:{requestBody}, Error:{ex.ToString()}");
                throw new Exception($"{method.ToString()}:{url} Error", ex);
            }

        }

        public T Execute<T>(string url, HttpMethod method, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            using (var httpClient = new HttpClient())
            {
                try
                {
                    // 发起GET请求
                    HttpResponseMessage response = httpClient.GetAsync(url).Result;

                    // 确保请求成功
                    response.EnsureSuccessStatusCode();

                    // 读取响应内容
                    string responseBody = response.Content.ReadAsStringAsync().Result;

                    var result = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseBody);
                    return result;
                }
                catch (HttpRequestException ex)
                {
                    _logger.LogError($"{method.ToString()}:{url},body:{requestBody}, Error:{ex.ToString()}");
                    throw new Exception($"{method.ToString()}:{url} Error", ex);
                }
            }

        }

        public async Task<RequesResult> ExecuteAsync(string url, HttpMethod method, string requestBody, Dictionary<string, string> dicHeaders, int timeoutSecond = 180)
        {
            try
            {
                var client = BuildHttpClient(null, timeoutSecond);
                var request = GenerateHttpRequestMessage(url, requestBody, method, dicHeaders);
                var response = await client.SendAsync(request);
                var responseContent = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    return RequesResult.ok().putdata("okdata", responseContent);
                }
                else
                {
                    //RequesError? error = Newtonsoft.Json.JsonConvert.DeserializeObject<RequesError>(responseContent);

                    return RequesResult.error().putdata("erdata", Newtonsoft.Json.JsonConvert.DeserializeObject<RequesError>(responseContent));
                    throw new CustomerHttpException(response.StatusCode.ToString(), responseContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"{method.ToString()}:{url},body:{requestBody}, Error:{ex.ToString()}");
                throw new Exception($"{method.ToString()}:{url} Error", ex);
            }

        }
        /// <summary>
        /// Build HttpClient
        /// </summary>
        /// <param name="timeoutSecond"></param>
        /// <returns></returns>
        private HttpClient BuildHttpClient(Dictionary<string, string> dicDefaultHeaders, int? timeoutSecond)
        {
            var httpClient = _httpClientFactory.CreateClient();
            httpClient.DefaultRequestHeaders.Clear();   //in order that the client is not affected by the last request,it need to clear DefaultRequestHeaders
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            if (dicDefaultHeaders != null)
            {
                foreach (var headerItem in dicDefaultHeaders)
                {
                    if (!httpClient.DefaultRequestHeaders.Contains(headerItem.Key))
                    {
                        httpClient.DefaultRequestHeaders.Add(headerItem.Key, headerItem.Value);
                    }
                }
            }
            if (timeoutSecond != (int?)null)
            {
                httpClient.Timeout = TimeSpan.FromSeconds(timeoutSecond.Value);
            }
            return httpClient;
        }

        /// <summary>
        /// Generate HttpRequestMessage
        /// </summary>
        /// <param name="url"></param>
        /// <param name="requestBody"></param>
        /// <param name="method"></param>
        /// <param name="dicHeaders"></param>
        /// <returns></returns>
        private HttpRequestMessage GenerateHttpRequestMessage(string url, string requestBody, HttpMethod method, Dictionary<string, string> dicHeaders)
        {
            var request = new HttpRequestMessage(method, url);
            if (!string.IsNullOrEmpty(requestBody))
            {
                //request.Content = new StringContent(requestBody);
                request.Content = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/json");
            }
            if (dicHeaders != null)
            {
                foreach (var header in dicHeaders)
                {
                    request.Headers.Add(header.Key, header.Value);
                }
            }

            return request;
        }
        /// <summary>
        ///  Generate StringContent
        /// </summary>
        /// <param name="requestBody"></param>
        /// <param name="dicHeaders"></param>
        /// <returns></returns>
        private StringContent GenerateStringContent(string requestBody, Dictionary<string, string> dicHeaders)
        {
            var content = new StringContent(requestBody);
            if (dicHeaders != null)
            {
                foreach (var headerItem in dicHeaders)
                {
                    content.Headers.Add(headerItem.Key, headerItem.Value);
                }
            }
            return content;
        }
    }

    public class CustomerHttpException : Exception
    {
        public string? ErrorCode { get; set; }
        public string? ErrorMessage { get; set; }
        public CustomerHttpException() : base()
        { }
        public CustomerHttpException(string errorCode, string errorMessage) : base()
        {
            ErrorCode = errorCode;
            ErrorMessage = ErrorMessage;
        }
    }
}
